require 'socket'
require 'esi'
require 'esi/tag'
require 'esi/base_parser'

module ESI

  # process a input stream in one pass
  # writing to the output stream as soon as the bytes appear to not be within an esi tag
  # this will maximize percieved response time, and allow the browser to get to downloading css/js faster
  # stop streaming on the first esi tag encountered, and continue parsing for esi tags, 
	# buffering and marking any new esi tags
  class PullParser < BaseParser
    attr_reader :fragment_params
    attr_accessor :fragment_pending
    attr_reader :parser

    def initialize(router)
      super
    end

    def process_io( options, &output_callback )
      input = options[:input_stream]
      head = options[:response_headers]
      request = options[:request]
      depth = options[:depth] || 0
      params = options[:http_params]

      @response = output_callback
      @stream_index = 0
      @overflow_buffers = []
      @fragment_buffers = []
      @fragment_params = params.reject{|k,v| k == 'Content-Type' || k == 'Content-Length' || k == 'Surrogate-Control' }

      @result_buffer = ""
      @fragment_pending = false
      @request_queue = []

      @parser = Mongrel::ESI::Parser.new( :buffer_ready => lambda {|buffer| stream_content( buffer ) }, 
                                          :esi_tag_ready => lambda {|tag,start| process_tag( tag, (start == 0) ) } )
      @parser.parse input.read
    end

    def stream_content( buffer )
      if buffer_ready?
        puts "streaming..."
        @response.call @result_buffer + buffer
        @result_buffer = ""
      else
        @result_buffer << buffer
      end
    end

    def cached?( url )
      @cache.is_cached?( url, @fragment_params )
    end

    def cache_store( url, ttl, data )
      @cache.cache_push( url, @fragment_params, ttl, data )
    end

    def cache_get( url )
      @cache.cached(url,@fragment_params).body
    end

    def url_for( src )
      @router.url_for( prepare_url_vars( src, @request ) )
    end

    def process_tag( tag, start )
      if start
        @tag = Tag.create(tag)
        puts @tag.inspect
        @tag.invoke( self )
      else
        @tag.end_tag( self )
      end
    end

    def buffer_ready?
      !@fragment_pending
    end

  end

end
